package cn.getech.data.development.utils.permission;


import cn.getech.data.development.config.properties.RangerConfig;
import cn.getech.data.development.constant.ApplyStatusEnum;
import cn.getech.data.development.entity.dataMap.DataApplication;
import cn.getech.data.development.entity.dataMap.DataApplicationExample;
import cn.getech.data.development.mapper.dataMap.DataApplicationMapper;
import cn.getech.data.development.model.ranger.RangerUser;
import cn.getech.data.development.service.RangerDataService;
import cn.getech.data.development.utils.spring.SpringContextUtil;
import cn.getech.data.intelligence.common.utils.DateUtils;
import cn.getech.system.center.constant.RangerRoleTypeEnum;
import cn.getech.system.center.model.dto.SysUserDto;
import cn.getech.system.center.service.SysUserService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @description: 到时更新权限过期状态
 * @author: wangzhaowen：kiss
 * @create: 2020/9/8 9:50
 * @version: 2020/9/8
 **/
@Slf4j
public class ApplyStatusUtil {

    // 创建延时队列
    private static DelayQueue<RunTask> queue = new DelayQueue<>();

    //初始化数据库中权限到期待更新状态的数据
    public static void init() {
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
        // private SysUserService sysUserService;
        // 启动消费线程 消费添加到延时队列中的消息，前提是任务到了延期时间
        DataApplicationMapper dataApplicationMapper = SpringContextUtil.getBean(DataApplicationMapper.class);
        singleThreadPool.execute(new Consumer(queue, dataApplicationMapper));
        DataApplicationExample param = new DataApplicationExample();
        List<Integer> status = new ArrayList<>(2);
        status.add(ApplyStatusEnum.PASS.getType());
        status.add(ApplyStatusEnum.WAIT.getType());
        param.createCriteria()
                //.andEffectiveDeadlineGreaterThan(new Date())
                .andApplyStatusIn(status);
        List<DataApplication> list = dataApplicationMapper.selectByExample(param);
        if (CollectionUtils.isNotEmpty(list)) {
            for (DataApplication dataApplication : list) {
                Long time = dataApplication.getEffectiveDeadline().getTime();
                addTask(dataApplication.getId(), time);
            }
        }
        RangerDataService rangerDataService = SpringContextUtil.getBean(RangerDataService.class);
        SysUserService sysUserService = SpringContextUtil.getBean(SysUserService.class);
        List<SysUserDto> userList = sysUserService.listAllUsers();
       //启动的时候同步一下用户信息
        if (CollectionUtils.isNotEmpty(userList)) {
            for (SysUserDto user : userList) {
                RangerUser rangerUser = wrapRangerUser(user);
                if (rangerDataService.getRangerUser(rangerUser.getName()) == null) {
                    RangerUser temp=rangerDataService.addRangerUser(rangerUser);
                    if (temp != null) {
                        log.info("同步用户到ranger中:{} name:{}", rangerUser.getName(), user.getUsername());
                    }else{
                        log.info("同步用户到ranger中:{} 失败:\n{}", rangerUser.getName(),
                                JSONObject.toJSONString(rangerUser));
                    }
                }
            }
        }
        // 使用队列延迟更新策略
       // rangerDataService.synUpdateRangerPolicy();
    }
    private static RangerUser wrapRangerUser(SysUserDto user){
        RangerUser rangerUser = new RangerUser();
        rangerUser.setName(RangerConfig.USER_PRE + user.getUserId());
        rangerUser.setPassword(rangerUser.getName()+rangerUser.getName());
        rangerUser.setFirstName(RangerConfig.USER_PRE + user.getUserId());
        rangerUser.setStatus(1);
        rangerUser.setIsVisible(1);
        rangerUser.setUserRoleList(Arrays.asList(RangerRoleTypeEnum.RANGER_USER.getName()));
        List<String> groupIds = new ArrayList<>();
        groupIds.add(RangerConfig.GROUP_ID);
        rangerUser.setGroupIdList(groupIds);
        return rangerUser;
    }


    /**
     * @param taskId  任务id
     * @param runTime 执行时间  对应 effectiveDeadline  时间
     * @Description: 添加任务
     * @return: void
     */
    public static void addTask(Long taskId, Long runTime) {
        RunTask t = new RunTask(taskId, runTime);
        addTask(t);
//        log.info("申请id{}权限过期时间：{}", taskId,
//                DateUtils.format(new Date(runTime)
//                        , DateUtils.DATE_TIME_PATTERN));
    }

    /**
     * @param taskId  任务id
     * @param runTime 对应 effectiveDeadline  时间
     * @Title: remove
     * @Description: 删除任务
     * @return: void
     */
    public static void remove(Long taskId, Long runTime) {
        RunTask t = new RunTask(taskId, runTime);
        remove(t);
    }

    /**
     * @param t
     * @Title: addTask
     * @Description: 添加任务
     * @return: void
     */
    public static void addTask(RunTask t) {
        queue.put(t);
    }

    /**
     * @param t 任务
     * @Title: remove
     * @Description: 删除任务
     * @return: void
     */
    public static void remove(RunTask t) {
        queue.remove(t);
    }

    public static class Consumer implements Runnable {
        // 延时队列 ,消费者从其中获取消息进行消费
        private DelayQueue<RunTask> queue;
        /**
         * 发送消息服务
         */
        private DataApplicationMapper dataApplicationMapper;

        public Consumer(DelayQueue<RunTask> queue, DataApplicationMapper dataApplicationMapper) {
            this.queue = queue;
            this.dataApplicationMapper = dataApplicationMapper;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    RunTask take = queue.take();
                    //更新状态
                    if (take.getTaskId() != null) {
                        DataApplication apply = dataApplicationMapper.selectByPrimaryKey(take.taskId);
                        if (apply != null) {
                            if (ApplyStatusEnum.WAIT.getType().equals(apply.getApplyStatus()) ||
                                    ApplyStatusEnum.PASS.getType().equals(apply.getApplyStatus())) {

                                if (ApplyStatusEnum.WAIT.getType().equals(apply.getApplyStatus())
                                        && StringUtils.isEmpty(apply.getRejectionReason())) {
                                    apply.setRejectionReason("有效时间已到，未有人审批，申请已过期");
                                }
                                apply.setApplyStatus(ApplyStatusEnum.EXPIRED.getType());
                                //apply.setHandleTime(new Date());
                                dataApplicationMapper.updateByPrimaryKeySelective(apply);
                                log.info("权限已经到期：申请id{}，申请人为：{}", apply.getId(), apply.getApplyUser());
                                //回收rang策略
                                RangerDataService rangerDataService = SpringContextUtil.getBean(RangerDataService.class);
                                rangerDataService.saveOrUpdateRangerPolicy(apply);
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    log.warn("更新权限先到期数据异常：{}", e.getMessage());
                }
            }
        }
    }

    public static class RunTask implements Delayed {
        /**
         * 任务id
         */
        private Long taskId;

        /**
         * 执行时间
         */
        private Long runTime;//

        /**
         * 任务类型  1 发提醒  2 更新状态  改为逾期
         */
        //private Integer type=1;
        public RunTask(Long taskId, Long runTime) {
            this.taskId = taskId;
            this.runTime = runTime;
        }

        @Override
        public int compareTo(Delayed o) {
            RunTask rt = (RunTask) o;
            long diff = this.runTime - rt.runTime;
            if (diff > 0) {
                return 1;
            } else if (diff < 0) {
                return -1;
            } else {
                return 0;
            }
        }

        @Override
        public long getDelay(TimeUnit unit) {
            long u = unit.convert(this.runTime
                    - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
            return u;
        }

        public Long getTaskId() {
            return taskId;
        }
    }
}
